繼前一章節 Day28 使用M3的Motion - Transition Patterns四種模式,其中的Container transform patterns (1)
此模式用於具有空間或導航關係的UI元素之間的過渡,該模式使用x、y或z軸上的共享變換來加強元素之間的關係。
MaterialSharedAxis使用向前或向後移動的概念,以下是MaterialSharedAxis向前和向後移動的軸線。
Axis | Forward | Backward | 動畫效果 |
---|---|---|---|
X | Left on x-axis | Right on x-axis | 水平滑動和淡入淡出 |
Y | Up on y-axis | Down on y-axis | 垂直滑動和淡入淡出 |
Z | Forward on z-axis | Backward on z-axis | 使用縮放和淡入淡出 |
x-axis 查看效果
y-axis 查看效果
z-axis 查看效果
Activity 和 Window過渡需要使用com.google.android.material.transition.platform提供的Android框架Transition,並且只能在API級別21及更高版本上可用。
準備兩個Class,和兩個 layout
設定Enable Activity Transitions,可以在主題xml、Activity的onCreate設定
<style name="MyTheme" parent="Theme.Material3.DayNight.NoActionBar">
...
<item name="android:windowActivityTransitions">true</item>
</style>
override fun onCreate(savedInstanceState: Bundle?) {
window.requestFeature(Window.FEATURE_ACTIVITY_TRANSITIONS)
...
}
Activity A 設定 MaterialSharedAxis,退出的動畫效果
Activity A’s Class 的onCreate設定:
設定Activity A關閉的設定axis、動畫開始效果 MaterialSharedAxis(MaterialSharedAxis.X, true)
查看源碼:
/**
* Params:axis設定X-axis、Y-axis、Z-axis
* Params:Boolean forward 設定動畫方向,**True**從左邊水平滑動,**False**從右邊水平滑動
**/
public MaterialSharedAxis(@Axis int axis, boolean forward) {
super(createPrimaryAnimatorProvider(axis, forward), createSecondaryAnimatorProvider());
this.axis = axis;
this.forward = forward;
}
指定動畫效果的layout id addTarget(android.R.id.content)
class SharedAxisActivityA: AppCompatActivity() {
private lateinit var binding: ActivitySharedAxisABinding
override fun onCreate(savedInstanceState: Bundle?) {
// 設定退出的動畫效果, MaterialSharedAxis,設定axis、動畫開始方向
window.exitTransition = MaterialSharedAxis(MaterialSharedAxis.X, true).apply {
// 指定動畫效果的layout id
addTarget(R.id.btn_axis_x)
}
super.onCreate(savedInstanceState)
binding = ActivitySharedAxisABinding.inflate(layoutInflater)
setContentView(binding.root)
// X 軸頁面切換動畫效果
binding.btnAxisX.setOnClickListener {
val bundle = ActivityOptions.makeSceneTransitionAnimation(this).toBundle()
startActivity(Intent(this, SharedAxisActivityB::class.java), bundle)
}
}
}
Activity A’s layout:
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto">
<Button
android:id="@+id/btn_axis_x"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="40dp"
android:text="X-Axis動畫效果"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"/>
<Button
android:id="@+id/btn_axis_y"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="40dp"
android:text="Y-Axis動畫效果"
app:layout_constraintTop_toBottomOf="@id/btn_axis_x"
app:layout_constraintStart_toStartOf="parent"/>
<Button
android:id="@+id/btn_axis_z"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="40dp"
android:text="Z-Axis動畫效果"
app:layout_constraintTop_toBottomOf="@id/btn_axis_y"
app:layout_constraintStart_toStartOf="parent"/>
Activity B 設定 MaterialSharedAxis 進入動畫效果
ActivityB’s Class 的onCreate設定:
MaterialSharedAxis(MaterialSharedAxis.X, true)
addTarget(android.R.id.content)
class SharedAxisActivityB: AppCompatActivity() {
private lateinit var binding: ActivitySharedAxisBBinding
override fun onCreate(savedInstanceState: Bundle?) {
// 設定進入動畫效果,MaterialSharedAxis,設定axis、動畫開始方向
window.enterTransition = MaterialSharedAxis(MaterialSharedAxis.X, true).apply {
// 指定動畫效果的layout id
addTarget(R.id.b_container)
}
// ActivityA 和 ActivityB 的動畫效果重疊,預設為True
// 當為 true 時,ActivityA轉換完成後再開始ActivityB
// 當為 false 時,轉換將不等到ActivityA退出轉換完成後再開始ActivityB
window.allowEnterTransitionOverlap = true
super.onCreate(savedInstanceState)
binding = ActivitySharedAxisBBinding.inflate(layoutInflater)
setContentView(binding.root)
}
}
Activity B’s layout:
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/b_container"
xmlns:app="http://schemas.android.com/apk/res-auto">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Activity B"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
Activity A 開啟 Activity B頁面
ActivityOptions
傳遞Bundle
,開啟Activity B頁面val bundle = ActivityOptions.makeSceneTransitionAnimation(this).toBundle()
startActivity(Intent(this, ActivityB::class.java), bundle)
接下來範例在Fragment A 和 Fragment B 之間使用Z軸的動畫效果
準備兩個Class,和兩個 layout
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// FragmentA關閉準備開啟FragmentB頁面時動畫
exitTransition = MaterialSharedAxis(MaterialSharedAxis.Z, /* forward= */ true)
// FragmentB頁面返回FragmentA時動畫
reenterTransition = MaterialSharedAxis(MaterialSharedAxis.Z, /* forward= */ false)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enterTransition = MaterialSharedAxis(MaterialSharedAxis.Z, /* forward= */ true)
returnTransition = MaterialSharedAxis(MaterialSharedAxis.Z, /* forward= */ false)
}
supportFragmentManager
.beginTransaction()
.replace(R.id.fragment_container, FragmentB())
.commit()
MaterialSharedAxis
是MaterialVisibility
擴充套件,MaterialVisibility
是一個Visibility過渡,由較小atomic
的VisibilityAnimatorProviders
組成,能夠根據目標是否出現還是消失來構建動畫。
預設情況下,MaterialVisibility
實現具有主要和次要VisibilityAnimatorProvider
,主要提供程式可以修改,而次要提供程式可以修改、替換或刪除。 這允許自定義動畫,同時仍然堅持圖案的基礎,被稱為variant
Shared axis 組成項目
Examples: 設定ActivityA使用 MaterialSharedAxis Z軸,預設會有輔助動畫效果,讓換頁時動畫會在ActivityA中和ActivityA上淡化效果,同時使ActivityA的alpha保持不變。
可查看源碼:createSecondaryAnimatorProvider()
方法開啟創建輔助動畫效果
public MaterialSharedAxis(@Axis int axis, boolean forward) {
super(createPrimaryAnimatorProvider(axis, forward), createSecondaryAnimatorProvider());
this.axis = axis;
this.forward = forward;
}
// 提供淡出或在視圖中的 Animator
private static VisibilityAnimatorProvider createSecondaryAnimatorProvider() {
return new FadeThroughProvider();
}
所以在客製化時,想移除預設會有輔助動畫效果,可以設定 secondaryAnimatorProvider = null
ActivityA‘s class:
override fun onCreate(savedInstanceState: Bundle?) {
val exit = MaterialSharedAxis(MaterialSharedAxis.Z, true).apply {
secondaryAnimatorProvider = null
addTarget(R.id.main_container)
}
window.exitTransition = exit
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
...
}
感謝耐心看到這邊~~
今日只講了Motion - Shared axis,明日繼續其他。